import { _decorator, Component, math, Node, Vec3, v3 } from 'cc';
import { Actor } from './Actor';
import { VirtualInput } from '../input/VirtualInput';
import { StateDefine } from './StateDefine';
import { ProjectileEmitter } from './ProjectileEmitter';

import { MathUtil } from '../utils/MathUtil';
import { ActorManager } from '../level/ActorManager';
import { Events } from '../events/Events';
import { AudioManager } from '../level/AudioManager';

const { ccclass, property, requireComponent } = _decorator;

let arrowForward:Vec3 = v3();

@ccclass('PlayerController')
@requireComponent(Actor)
@requireComponent(ProjectileEmitter)
export class PlayerController extends Component {

    actor:Actor = null;

    @property(Node)
    bowString:Node = null;

    projectileEmitter: ProjectileEmitter;

    private _splitAngle: number[] = [0];

    start() {
        this.actor = this.node.getComponent(Actor);

        this.projectileEmitter =  this.node.getComponent(ProjectileEmitter);

        this.node.on("onFrameAttackLoose", this.onFrameAttackLoose, this);

        ActorManager.instance.playActor = this.actor;

        this.node.on(Events.OnKill, this.onKill, this); 


        this.ProjectileCount  = this.actor.actorProperty.projectileCount;

    }

    onDestroy() {
        ActorManager.instance.playActor = null;
    }


    onKill(){
        let property = this.actor.actorProperty;
        property.exp++;

        if(property.exp >= property.maxExp){
            property.exp = 0;

            property.maxExp *= 1.2;
            property.level++;
            this.node.emit(Events.OnPlayerUpgrade, property.level);
        }

        this.node.emit(Events.OnExpGain, property.exp, property.maxExp);

    }

    update(deltaTime: number) {

        if (this.actor.currState == StateDefine.Die || this.actor.currState == StateDefine.Hit) {
            return;
        }

        const len = this.handleInput();

        if (len > 0.1) {
            this.actor.changeState(StateDefine.Run);
        } else{
            let enemy = this.getNearEnemy();
            if(enemy == null){
                this.actor.changeState(StateDefine.Idle);
            }else{
                // 修改角色朝向
                Vec3.subtract(this.actor.input, enemy.worldPosition, this.node.worldPosition);
                this.actor.input.y = 0;
                this.actor.input.normalize();

                this.actor.changeState(StateDefine.Attack);
            }
        }
    }

    getNearEnemy():Node{
        let enemies = ActorManager.instance.enemies;
        if (!enemies || enemies?.length == 0) {
            return null;
        }

        let minDistance = 9999;
        let minNode:Node = null;

        for(let enemy of enemies){
            const actor = enemy.getComponent(Actor);
            if (actor.currState == StateDefine.Die) {
                continue;
            }
            let distance = Vec3.distance(this.node.worldPosition, enemy.worldPosition);
            if( distance < minDistance){
                minDistance = distance;
                minNode = enemy;
            }
        }

        // 可以给定最远攻击距离
        return minNode;
    }



    onFrameAttackLoose()
    {
        // 发送箭
        const arrowStartPos = this.bowString.worldPosition;
       
        for(let i = 0; i < this.actor.actorProperty.projectileCount; i++)
        {
            let projectile = this.projectileEmitter.create();
            // 调整每个箭的发射角度
            MathUtil.rotateAround(arrowForward, this.node.forward, Vec3.UP, this._splitAngle[i]);
            projectile.node.forward = arrowForward.clone();
            
            projectile?.fire();
            projectile.host = this.node;
            projectile.node.worldPosition = arrowStartPos;
        }

        // 播放发射音效
        AudioManager.instance.playShootSfx();
    }

    set ProjectileCount(count: number){
        this._splitAngle = [];
        const rad = math.toRadian(10);
        const isOdd = count % 2 != 0;

        const len = Math.floor(count / 2);
        for (let i = 0; i < len; i++)
        {
            this._splitAngle.push(-rad * (i + 1));
            this._splitAngle.push(rad * (i + 1));
        }

        if(isOdd)
        {
            this._splitAngle.push(0)
        }

    }


    handleInput(): number {
        let x = VirtualInput.horizontal;
        let y = VirtualInput.vertical;

        this.actor.input.x = x;
        this.actor.input.z = -y;
        this.actor.input.y = 0;
        this.actor.input.normalize();
        return this.actor.input.length();
    }
}

